// ==UserScript==
// @name            双向通信-油猴端
// @namespace       http://tampermonkey.net/
// @version         0.4
// @description     与Python双向通信，基于localStorage+时间戳优化轮询
// @author          豆包
// @match           https://chat.deepseek.com/*
// @match           https://yuanbao.tencent.com/chat/*
// @match           https://yuanbao.tencent.com/*
// @match           http://yuanbao.tencent.com/*
// @match           https://*.tencent.com/*
// @match           http://localhost/*
// @match           http://127.0.0.1/*
// @match           file:///*
// @grant           none
// @run-at          document-start
// @homepage        https://gitee.com/luzhishen666/auto-ai-messenger
// @downloadURL     https://gitee.com/luzhishen666/auto-ai-messenger/master/tampermonkey.user.js
// @updateURL       https://gitee.com/luzhishen666/auto-ai-messenger/master/tampermonkey.user.js
// @supportURL      https://gitee.com/luzhishen666/auto-ai-messenger/issues
// ==/UserScript==

(function () {
    'use strict';

    /**
     * Python ↔ 油猴双向通信脚本
     * 基于localStorage + 时间戳的双向通信机制
     * 
     * 通信流程：
     * 1. 油猴脚本通过localStorage发送消息给Python
     * 2. Python程序轮询读取localStorage并回复
     * 3. 油猴脚本轮询读取Python的回复并显示
     * 
     * 防重复机制：通过时间戳确保只处理新消息
     */

    /**
     * AI配置基类，定义所有AI平台通用的接口
     * @class
     */
    class AIConfig {
        /**
         * 创建AI配置实例
         * @param {string} name - AI平台名称
         */
        constructor(name) {
            this.name = name;
            this.lastConversationCounter = 0;
        }
        /**
         * 获取输入框元素
         * @returns {HTMLElement|null} 输入框元素或null
         */
        getInputElement() { return null; }
        /**
         * 获取对话列表
         * @returns {HTMLElement[]|null} 对话列表元素数组或null
         */
        getConversationList() { return null; }
        /**
         * 获取当前对话计数
         * @returns {number} 对话数量
         */
        getConversationCounter() {
            let conversationList = this.getConversationList();
            return conversationList ? conversationList.length : 0;
        }
        /**
         * 检查AI回复是否完成
         * @returns {boolean} 回复是否完成
         */
        isReplyCompleted() { return this.getConversationCounter() === this.lastConversationCounter; }
        /**
         * 检查是否可以发送下一条消息
         * @returns {boolean} 是否可以发送下一条消息
         */
        canSendNextMessage() {
            let currentConversationCounter = this.getConversationCounter();
            if (!currentConversationCounter || currentConversationCounter === this.lastConversationCounter) {
                return true;
            }
            let conversationList = this.getConversationList();
            // 检查conversationList是否为null或undefined
            if (!conversationList) {
                return true;
            }
            // （新增了一问一答） && （出现了操作按钮，说明AI已经完整输出了回复）  
            if (currentConversationCounter - this.lastConversationCounter === 2
                && this.isAIOutputOver(conversationList[conversationList.length - 1])) {
                this.lastConversationCounter = currentConversationCounter;
                return true;
            }
            return false;
        }
        /**
         * 检查AI输出是否完成（需要子类实现）
         * @param {HTMLElement} lastConversation - 最后一个对话元素
         * @returns {boolean} AI输出是否完成
         */
        isAIOutputOver(lastConversation) { return false; }
        /**
         * 在接收第一条消息前初始化对话计数
         */
        beforeReceiveFirstMessage() { this.lastConversationCounter = this.getConversationCounter(); }
        /**
         * 填充并发送消息
         * @param {string} message - 要发送的消息
         * @returns {Promise<boolean>} 发送是否成功
         */
        async fillAndSendMessage(message) { return false; }
        /**
         * 获取发送按钮
         * @returns {HTMLElement|null} 发送按钮元素或null
         */
        getSendButton() { return null; }
        /**
         * 发送消息
         * @returns {Promise<boolean>} 发送是否成功
         */
        async sendMessage() { return false; }
        async getReply() { return null; }
    }

    /**
     * DeepSeek AI平台配置类
     * @class
     * @extends AIConfig
     */
    class DeepSeekAIConfig extends AIConfig {
        /**
         * 创建DeepSeek AI配置实例
         */
        constructor() {
            super('DeepSeek');
        }
        /**
         * 获取DeepSeek输入框元素
         * @returns {HTMLTextAreaElement|null} 输入框元素或null
         */
        getInputElement() {
            return document.querySelector('textarea[placeholder="给 DeepSeek 发送消息 "]') ||
                document.querySelector('textarea');
        }
        /**
         * 获取DeepSeek对话列表
         * @returns {HTMLCollection|null} 对话列表元素集合或null
         */
        getConversationList() {
            const spanOpenNewConversation = document.evaluate("//span[text()='开启新对话']", document, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null).snapshotItem(1);
            if (!spanOpenNewConversation) {
                debugLog('未找到开启新对话按钮');
                return null;
            }
            const lastConversationDiv = spanOpenNewConversation.parentElement.parentElement.previousElementSibling;
            return lastConversationDiv.children;
        }
        /**
         * 检查DeepSeek AI输出是否完成
         * @param {HTMLElement} lastConversation - 最后一个对话元素
         * @returns {boolean} AI输出是否完成
         */
        isAIOutputOver(lastConversation) {
            return lastConversation.children.length === 3;
        }
        /**
         * 创建输入框保护机制，防止文本被意外清空
         * @param {HTMLTextAreaElement} input - 输入框元素
         * @param {string} text - 要保护的文本内容
         * @returns {Object} 保护对象
         */
        createInputProtection(input, text) {
            const originalBlur = input.blur;
            const originalValue = input.value;
            const originalFocus = input.focus;

            // 创建保护对象，使用对象属性而不是闭包变量
            const protection = {
                isProtected: true,
                originalBlur,
                originalFocus,
                originalValue
            };

            // 重写blur方法
            input.blur = function () {
                if (protection.isProtected) {
                    debugLog('输入框blur被调用，但被阻止以防止文本清空');
                    return;
                }
                originalBlur.call(this);
            };

            // 重写focus方法以确保始终有焦点
            input.focus = function () {
                originalFocus.call(this);
                this.selectionStart = this.selectionEnd = this.value.length;
            };

            // 添加输入值保护
            Object.defineProperty(input, 'value', {
                get: function () {
                    return this._protectedValue || originalValue;
                },
                set: function (newValue) {
                    if (protection.isProtected && newValue === '') {
                        debugLog('检测到输入框值被清空，阻止此操作');
                        this._protectedValue = text;
                        const inputEvent = new Event('input', { bubbles: true, cancelable: true });
                        this.dispatchEvent(inputEvent);
                        return;
                    }
                    this._protectedValue = newValue;
                },
                configurable: true
            });

            return protection;
        }
        /**
         * 完成输入并清理保护机制
         * @param {HTMLTextAreaElement} input - 输入框元素
         * @param {Object} protection - 保护对象
         * @param {Function} resolve - Promise resolve函数
         */
        completeInputAndCleanup(input, protection, resolve) {
            debugLog('✅ 键盘模拟输入完成');
            debugLog('📝 最终值:', input.value);

            // 解除保护
            protection.isProtected = false;
            this.removeInputProtection(input, protection);

            // 触发所有必要的事件来确保发送按钮状态更新
            const finalEvents = ['input', 'change', 'blur', 'focus'];
            finalEvents.forEach(eventType => {
                const event = new Event(eventType, { bubbles: true, cancelable: true });
                input.dispatchEvent(event);
            });

            // 保持焦点，防止文字被清空
            input.focus();
            input.selectionStart = input.selectionEnd = input.value.length;

            resolve();
        }
        /**
         * 移除输入框保护机制
         * @param {HTMLTextAreaElement} input - 输入框元素
         * @param {Object} protection - 保护对象
         */
        removeInputProtection(input, protection) {
            input.blur = protection.originalBlur;
            input.focus = protection.originalFocus;
            Object.defineProperty(input, 'value', {
                get: function () {
                    return this._protectedValue || '';
                },
                set: function (newValue) {
                    this._protectedValue = newValue;
                },
                configurable: true
            });
        }
        /**
         * 触发键盘事件
         * @param {HTMLTextAreaElement} input - 输入框元素
         * @param {string} char - 字符
         */
        triggerKeyboardEvents(input, char) {
            const keyEvents = ['keydown', 'keypress', 'keyup'];
            keyEvents.forEach(eventType => {
                const event = new KeyboardEvent(eventType, {
                    key: char,
                    code: `Key${char.toUpperCase()}`,
                    keyCode: char.charCodeAt(0),
                    which: char.charCodeAt(0),
                    bubbles: true,
                    cancelable: true
                });
                input.dispatchEvent(event);
            });
        }
        /**
         * 触发中文输入法事件
         * @param {HTMLTextAreaElement} input - 输入框元素
         * @param {string} char - 字符
         */
        triggerCompositionEvents(input, char) {
            if (/[一-鿿]/.test(char)) {
                // 触发compositionstart
                const compStartEvent = new CompositionEvent('compositionstart', {
                    bubbles: true,
                    cancelable: true,
                    data: char
                });
                input.dispatchEvent(compStartEvent);

                // 触发compositionupdate
                const compUpdateEvent = new CompositionEvent('compositionupdate', {
                    bubbles: true,
                    cancelable: true,
                    data: char
                });
                input.dispatchEvent(compUpdateEvent);

                // 触发compositionend
                const compEndEvent = new CompositionEvent('compositionend', {
                    bubbles: true,
                    cancelable: true,
                    data: char
                });
                input.dispatchEvent(compEndEvent);
            }
        }
        /**
         * 填充并发送消息到DeepSeek
         * @param {string} message - 要发送的消息
         * @returns {Promise<boolean>} 发送是否成功
         */
        async fillAndSendMessage(message) {
            debugLog('fillAndSendMessage被调用，文本:', message);
            const input = this.getInputElement();
            if (!input) {
                debugLog('未找到输入框');
                updateStatus("未找到输入框");
                return false;
            }
            // 创建保护机制
            const protection = this.createInputProtection(input, message);

            // 清空输入框并设置焦点
            protection.isProtected = false;
            input.focus();
            input.value = '';
            input.selectionStart = input.selectionEnd = 0;
            protection.isProtected = true;

            // 触发清空事件
            const clearEvent = new Event('input', { bubbles: true, cancelable: true });
            input.dispatchEvent(clearEvent);

            debugLog('开始模拟键盘输入:', message);

            // 使用Promise包装的键盘模拟输入
            const typeTextWithKeyboardSimulation = () => {
                return new Promise((resolve) => {
                    let currentIndex = 0;

                    const typeNextChar = () => {
                        if (currentIndex >= message.length) {
                            this.completeInputAndCleanup(input, protection, resolve);
                            return;
                        }

                        const char = message[currentIndex];

                        // 强制保持焦点
                        input.focus();

                        // 获取当前光标位置
                        const startPos = input.selectionStart;
                        const endPos = input.selectionEnd;

                        // 在当前光标位置插入字符
                        input.value = input.value.substring(0, startPos) + char + input.value.substring(endPos);

                        // 更新光标位置
                        input.selectionStart = input.selectionEnd = startPos + 1;

                        // 触发键盘事件
                        this.triggerKeyboardEvents(input, char);

                        // 触发中文输入法事件
                        this.triggerCompositionEvents(input, char);

                        // 触发input事件
                        const inputEvent = new InputEvent('input', {
                            bubbles: true,
                            cancelable: true,
                            data: char,
                            inputType: 'insertText'
                        });
                        input.dispatchEvent(inputEvent);

                        currentIndex++;

                        // 使用setTimeout继续下一个字符，确保所有字符都能正确输入
                        if (currentIndex < message.length) {
                            setTimeout(typeNextChar, 50);
                        } else {
                            // 当输入完所有字符时，调用completeInputAndCleanup
                            this.completeInputAndCleanup(input, protection, resolve);
                        }
                    };

                    // 立即开始输入第一个字符
                    typeNextChar();
                });
            };

            try {
                // 等待键盘模拟输入完成
                await typeTextWithKeyboardSimulation();
                debugLog('当前输入框值（发送前）:', input.value);

                // 等待UI更新
                await wait(500);
                // 发送消息并等待发送完成
                const sendSuccess = await this.sendMessage();
                debugLog('消息发送结果:', sendSuccess);
                // 确保解除保护
                this.removeInputProtection(input, protection);

                return sendSuccess;
            } catch (error) {
                debugLog('键盘模拟输入过程中出错:', error);
                // 确保解除保护
                this.removeInputProtection(input, protection);
                return false;
            }
        }
        /**
         * 获取DeepSeek发送按钮
         * @returns {HTMLElement|null} 发送按钮元素或null
         */
        getSendButton() {
            const searchFromWebButton = document.evaluate(
                "//span[text()='联网搜索']",
                document,  // 上下文节点
                null,      // 命名空间解析器（无需时为null）
                XPathResult.FIRST_ORDERED_NODE_TYPE,  // 结果类型：第一个匹配节点
                null       // 现有结果（无需时为null）
            ).singleNodeValue;
            return searchFromWebButton ? searchFromWebButton.parentElement.parentElement.nextElementSibling.children[2] : null;
        }
        /**
         * 发送消息到DeepSeek
         * @returns {Promise<boolean>} 发送是否成功
         */
        async sendMessage() {
            const input = this.getInputElement();
            debugLog('sendMessage被调用，当前输入框值:', input ? input.value : '无输入框');

            if (!input || input.value.trim() === '') {
                debugLog('输入框为空或未找到，无法发送消息');
                return false;
            }

            // 确保输入框有焦点
            input.focus();
            input.selectionStart = input.selectionEnd = input.value.length;

            // 先触发input和change事件确保UI更新
            const inputEvent = new Event('input', { bubbles: true, cancelable: true });
            input.dispatchEvent(inputEvent);

            const changeEvent = new Event('change', { bubbles: true, cancelable: true });
            input.dispatchEvent(changeEvent);


            /*   
            debugLog('使用Enter键发送消息');
            // 触发完整的Enter键事件序列
            const enterEvents = ['keydown', 'keypress', 'keyup'];
            enterEvents.forEach(eventType => {
                const enterEvent = new KeyboardEvent(eventType, {
                    key: 'Enter',
                    code: 'Enter',
                    keyCode: 13,
                    which: 13,
                    bubbles: true,
                    cancelable: true,
                    composed: true,
                    // 添加更多标准属性
                    charCode: eventType === 'keypress' ? 13 : 0,
                    detail: 0,
                    view: window,
                    repeat: false
                });

                input.dispatchEvent(enterEvent);
            });
            */
            let sendButton = this.getSendButton();
            if (sendButton) {
                sendButton.click();
            }
            await wait(1000);
            debugLog('消息已发送');
            return true;
        }
        async getReply() {
            const isCompleted = await waitUntil(() => this.isReplyCompleted(), 1000, 120); // 最多等待60次（60秒）
            if (!isCompleted) {
                console.warn('等待AI回复完成超时');
                return null;
            }
            let conversations = this.getConversationList();
            if (conversations.length > 0) {
                let lastConversation = conversations[conversations.length - 1];
                let level1 = lastConversation.children[0];
                let level2 = level1.children[this.isDeepSeekMode() ? 1 : 0];
                let pList = level2.querySelectorAll('.ds-markdown-paragraph');
                let reply = '';
                for (let p of pList) {                    
                    reply += p.innerText;
                }
                debugLog(`AI回复: ${reply}`);
                return reply;
            }
            return null;
        }
        /** 是否处于深度思考模式 */
        isDeepSeekMode() {
            let b = document.evaluate(
                "//span[text()='深度思考']",
                document,  // 上下文节点
                null,      // 命名空间解析器（无需时为null）
                XPathResult.FIRST_ORDERED_NODE_TYPE,  // 结果类型：第一个匹配节点
                null       // 现有结果（无需时为null）
            ).singleNodeValue;
            let t = b.parentElement.previousElementSibling;
            return getComputedStyle(t).color == 'rgb(57, 100, 254)';// 该颜色为深度思考状态
        }
    }
    /**
     * 元宝AI平台配置类
     * @class
     * @extends AIConfig
     */
    class YuanBaoAIConfig extends AIConfig {
        /**
         * 创建元宝AI配置实例
         */
        constructor() {
            super('YuanBao');
        }
        /**
         * 获取元宝AI输入框元素
         * @returns {HTMLElement|null} 输入框元素或null
         */
        getInputElement() {
            return document.querySelector('.ql-editor').querySelector('p');
        }
        /**
         * 获取元宝AI对话列表
         * @returns {NodeList|null} 对话列表元素集合或null
         */
        getConversationList() {
            return document.querySelectorAll('.agent-chat__list__item');
        }
        /**
         * 检查元宝AI输出是否完成
         * @param {HTMLElement} lastConversation - 最后一个对话元素
         * @returns {boolean} AI输出是否完成
         */
        isAIOutputOver(lastConversation) {
            let r = lastConversation.querySelector('.agent-chat__conv--ai__toolbar:not(.agent-chat__conv--ai__toolbar--loading)');
            //debugLog('isAIOutputOver检查结果:', r);
            return r;
        }
        /**
         * 填充并发送消息到元宝AI
         * @param {string} message - 要发送的消息
         * @returns {Promise<boolean>} 发送是否成功
         */
        async fillAndSendMessage(message) {
            debugLog('fillAndSendMessage被调用，文本:', message);
            let input = this.getInputElement();
            if (!input) {
                debugLog('未找到输入框');
                updateStatus("未找到输入框");
                return false;
            }

            // 设置输入框内容
            input.innerText = message;

            // 触发必要的事件来确保UI更新
            const inputEvent = new Event('input', { bubbles: true, cancelable: true });
            input.dispatchEvent(inputEvent);

            const changeEvent = new Event('change', { bubbles: true, cancelable: true });
            input.dispatchEvent(changeEvent);

            // 等待UI更新
            await wait(500);
            // 发送消息并等待发送完成
            const sendSuccess = await this.sendMessage();
            debugLog('消息发送结果:', sendSuccess);

            return sendSuccess;
        }
        /**
         * 获取元宝AI发送按钮
         * @returns {HTMLElement|null} 发送按钮元素或null
         */
        getSendButton() {
            return document.querySelector('#yuanbao-send-btn');
        }
        /**
         * 发送消息到元宝AI
         * @returns {Promise<boolean>} 发送是否成功
         */
        async sendMessage() {
            let sendButton = this.getSendButton();
            if (sendButton) {
                sendButton.click();
                // 等待消息发送完成
                await wait(1000); // 等待1秒确保发送完成
                debugLog('元宝AI消息发送完成');
                return true;
            }
            debugLog('未找到发送按钮');
            return false;
        }
        async getReply() {
            const isCompleted = await waitUntil(() => this.isReplyCompleted(), 1000, 120); // 最多等待60次（60秒）
            if (!isCompleted) {
                console.warn('等待AI回复完成超时');
                return null;
            }
            let conversations = this.getConversationList();
            if (conversations.length > 0) {
                let lastConversation = conversations[conversations.length - 1];
                return lastConversation.querySelector('.hyc-common-markdown').innerText;
            }
            return null;
        }
    }

    /** 调试模式开关 */
    const DEBUG = false;
    let aiConfig = null;
    /**
     * 根据当前URL设置对应的AI配置实例
     * 自动检测当前访问的AI平台并创建相应的配置对象
     * @returns {void}
     */
    (function setAIConfig() {
        const currentUrl = window.location.href;
        if (currentUrl.includes('chat.deepseek.com')) {
            aiConfig = new DeepSeekAIConfig();
        } else if (currentUrl.includes('yuanbao.tencent.com')) {
            aiConfig = new YuanBaoAIConfig();
        } else {
            debugLog('未识别的AI平台URL:', currentUrl);
            // 在面板上显示错误信息并终止脚本运行
            const errorMessage = `❌ 未识别的AI平台URL: ${currentUrl}\n脚本已终止运行`;
            
            // 创建UI并显示错误信息
            createUI();
            const receiveArea = document.getElementById('receiveArea');
            if (receiveArea) {
                receiveArea.innerHTML = `<div style="color: #CC0000; font-weight: bold; white-space: pre-wrap;">${errorMessage}</div>`;
            }
            
            // 终止整个脚本运行
            console.error('未识别的AI平台URL，脚本终止运行:', currentUrl);
            aiConfig = null;
            
            // 完全终止脚本：移除所有事件监听器，停止所有定时器
            if (typeof GM_registerMenuCommand !== 'undefined') {
                // 如果是油猴脚本环境，可以尝试卸载脚本
                window.addEventListener('beforeunload', function() {
                    // 清理资源
                    if (window.pollInterval) {
                        clearInterval(window.pollInterval);
                    }
                });
            }
            
            // 抛出错误终止脚本执行
            throw new Error(`未识别的AI平台URL: ${currentUrl}，脚本已终止运行`);
        }
        debugLog('最终aiConfig:', aiConfig ? aiConfig.name : 'null');
    })();

    // 1. 初始化状态：记录上次处理的时间戳（避免重复处理）
    let lastPyTimestamp = 0; // 上次处理Python发送数据的时间戳

    // 消息缓存队列
    let messageQueue = [];
    let isProcessingQueue = false;

    /**
     * 更新状态显示
     * 
     * 状态类型：
     * - waiting_python: 等待Python消息
     * - sending_to_ai: 发送消息给AI
     * - waiting_ai_reply: 等待AI回复完毕
     * - sending_to_python: 将AI回复发送给Python
     */
    function updateStatus(statusType) {
        const receiveArea = document.getElementById('receiveArea');
        if (!receiveArea) return;
        
        const statusMessages = {
            waiting_python: '🔄 等待Python消息...',
            sending_to_ai: '📤 发送消息给AI...',
            waiting_ai_reply: '⏳ 等待AI回复完毕...',
            sending_to_python: '📥 将AI回复发送给Python...'
        };
        
        const message = statusMessages[statusType] || '未知状态';
        receiveArea.innerHTML = `<div style="color: #666; font-weight: bold;">${message}</div>`;
    }

    /**
     * 创建双向通信交互框
     * 
     * 功能：
     * - 创建固定在页面右上角的通信UI，支持折叠/展开
     * - 显示Python回复的消息
     * 
     * UI结构：
     * - 折叠/展开按钮
     * - 标题：Python-油猴双向通信
     * - 状态显示区域：显示通信状态
     * 
     * 特点：
     * - 紧贴窗口最右上角（top: 20px, right: 20px）
     * - 不受窗口大小影响（position: fixed）
     */
    function createUI() {
        try {
            // 检查是否已经存在UI容器，避免重复创建
            if (document.getElementById('tampermonkey-communication-ui')) {
                console.log('油猴通信UI已存在，跳过创建');
                return;
            }

            // 创建UI容器
            const container = document.createElement('div');
            container.id = 'tampermonkey-communication-ui';
            // 设置UI样式：紧贴窗口最右上角，不受窗口大小影响
            container.style.cssText = `
                position: fixed; top: 20px; right: 20px; z-index: 9999;
                transition: all 0.3s ease;
            `;
            
            // UI HTML结构：包含折叠按钮和内容区域
            container.innerHTML = `
                <div style="display: flex; align-items: flex-start;">
                    <!-- 折叠/展开按钮 -->
                    <button id="toggleBtn" style="
                        width: 30px; height: 60px; 
                        background: #007bff; color: white; 
                        border: none; border-radius: 5px 0 0 5px;
                        cursor: pointer; font-size: 16px;
                        display: flex; align-items: center; justify-content: center;
                    ">▶</button>
                    
                    <!-- 内容区域 -->
                    <div id="contentArea" style="
                        width: 250px; background: #fff; 
                        border: 1px solid #ddd; border-radius: 0 8px 8px 0;
                        box-shadow: 0 4px 12px rgba(0,0,0,0.1);
                        padding: 12px;
                        transition: all 0.3s ease;
                    ">
                        <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 8px;">
                            <h4 style="margin: 0; color: #333; font-size: 14px;">Python-油猴通信</h4>
                        </div>
                        <!-- 状态显示区域 -->
                        <div>
                            <p style="margin: 3px 0; font-weight: bold; color: #666; font-size: 12px;">通信状态：</p>
                            <div id="receiveArea" style="min-height: 40px; max-height: 150px; overflow-y: auto; border: 1px solid #eee; padding: 6px; word-break: break-all; background: #f9f9f9; border-radius: 4px; font-size: 12px;">
                                <div style="color: #666; font-weight: bold;">🔄 等待Python消息...</div>
                            </div>
                        </div>
                    </div>
                </div>
            `;

            // 确保body元素存在后再添加UI
            if (document.body) {
                document.body.appendChild(container);
                console.log('油猴通信UI创建成功');
                
                // 添加折叠/展开功能
                const toggleBtn = document.getElementById('toggleBtn');
                const contentArea = document.getElementById('contentArea');
                let isCollapsed = false;
                
                toggleBtn.addEventListener('click', function() {
                    isCollapsed = !isCollapsed;
                    
                    if (isCollapsed) {
                        // 折叠状态
                        contentArea.style.width = '0';
                        contentArea.style.padding = '0';
                        contentArea.style.opacity = '0';
                        contentArea.style.overflow = 'hidden';
                        toggleBtn.innerHTML = '◀';
                        toggleBtn.style.borderRadius = '5px 0 0 5px';
                    } else {
                        // 展开状态
                        contentArea.style.width = '250px';
                        contentArea.style.padding = '12px';
                        contentArea.style.opacity = '1';
                        contentArea.style.overflow = 'visible';
                        toggleBtn.innerHTML = '▶';
                        toggleBtn.style.borderRadius = '5px 0 0 5px';
                    }
                });
                
            } else {
                console.error('body元素不存在，无法创建UI');
                return;
            }

        } catch (error) {
            console.error('创建油猴通信UI失败：', error);
        }
    }

    /**
     * 发送数据给Python
     * 
     * 功能：
     * - 获取输入框内容
     * - 生成当前时间戳（毫秒级）
     * - 构造JSON数据格式：{"data": 内容, "timestamp": 时间戳}
     * - 写入localStorage供Python读取
     * - 清空输入框
     * 
     * 防重复机制：每次发送都生成新的时间戳
     */
    function sendMessageToPython(message = null) {
        if (!message) return;
        const nowTimestamp = Date.now(); // 当前时间戳（毫秒级）
        // 构造数据格式：含数据+时间戳
        const data = JSON.stringify({
            data: message,
            timestamp: nowTimestamp
        });
        // 写入localStorage，键名为'tampermonkey_to_py'
        localStorage.setItem('tampermonkey_to_py', data);
    }

    /**
     * 轮询读取Python发送的数据
     * 
     * 功能：
     * - 从localStorage读取Python发送的数据
     * - 解析JSON数据格式
     * - 检查时间戳，只处理比上次更新的数据
     * - 将消息缓存到队列中
     * - 启动队列处理
     * 
     * 防重复机制：通过时间戳比较确保只处理新数据
     */
    function pollPythonData() {
        setInterval(() => {
            const pyDataStr = localStorage.getItem('py_to_tampermonkey');
            if (!pyDataStr) return;

            try {
                const pyData = JSON.parse(pyDataStr);
                // 核心：仅处理时间戳比上次大的新数据
                if (pyData.timestamp > lastPyTimestamp) {
                    // 更新状态：收到Python消息
                    updateStatus('waiting_python');
                    
                    // 将消息添加到缓存队列
                    messageQueue.push({
                        data: pyData.data,
                        timestamp: pyData.timestamp
                    });
                    console.log('收到Python消息，已添加到缓存队列，当前队列长度：', messageQueue.length);

                    // 更新最后处理的时间戳
                    lastPyTimestamp = pyData.timestamp;

                    // 启动队列处理（如果未在处理中）
                    if (!isProcessingQueue) {
                        processMessageQueue();
                    }
                }
            } catch (e) {
                console.error('解析Python数据失败：', e);
            }
        }, 500); // 轮询间隔：500ms，可调整
    }

    /**
     * 处理消息队列
     * 
     * 功能：
     * - 从队列中取出消息
     * - 等待AI可发送状态
     * - 发送消息给AI并获取回复
     * - 将回复发送给Python
     * - 处理队列中的下一条消息
     * 
     * 队列处理机制：
     * - 按先进先出(FIFO)顺序处理
     * - 等待AI可用状态后再发送
     * - 确保消息按顺序处理
     */
    async function processMessageQueue() {
        if (isProcessingQueue || messageQueue.length === 0) {
            return;
        }

        isProcessingQueue = true;

        try {
            while (messageQueue.length > 0) {
                const messageObj = messageQueue[0]; // 获取队列第一条消息
                console.log('开始处理队列消息，当前队列长度：', messageQueue.length);

                // 更新状态：发送消息给AI
                updateStatus('sending_to_ai');

                // 等待AI可以发送下一条消息
                const canSend = await waitUntil(() => aiConfig.canSendNextMessage(), 1000, 120); // 最多等待120次（120秒）
                if (!canSend) {
                    console.warn('等待AI可发送状态超时，跳过当前消息');
                    messageQueue.shift(); // 移除当前消息
                    continue;
                }

                // 发送消息给AI
                const success = await aiConfig.fillAndSendMessage(messageObj.data);
                if (success) {
                    // 更新状态：等待AI回复完毕
                    updateStatus('waiting_ai_reply');
                    
                    // 等待一下，确保出现"开启新对话"
                    await wait(2000);
                    // canSendNextMessage()内会修改lastConversionCounter
                    const canSendAgain = await waitUntil(() => aiConfig.canSendNextMessage(), 1000, 120); // 最多等待120次（120秒）
                    if (!canSendAgain) {
                        console.warn('等待AI再次可发送状态超时，跳过获取回复');
                        messageQueue.shift(); // 移除当前消息
                        continue;
                    }
                    // 获取AI回复
                    let reply = await aiConfig.getReply();

                    // 更新状态：将AI回复发送给Python
                    updateStatus('sending_to_python');

                    // 将回复发送给Python
                    sendMessageToPython(reply);
                    console.log('AI回复已发送给Python，队列长度：', messageQueue.length);
                }

                // 从队列中移除已处理的消息
                messageQueue.shift();
                
                // 更新状态：等待Python消息
                updateStatus('waiting_python');
            }
        } catch (error) {
            console.error('处理消息队列时出错：', error);
        } finally {
            isProcessingQueue = false;

            // 检查是否还有新消息需要处理
            if (messageQueue.length > 0) {
                console.log('队列中还有消息，继续处理');
                setTimeout(() => processMessageQueue(), 100);
            }
        }
    }

    /**
     * 初始化脚本
     * 
     * 功能：
     * - 清除localStorage中的历史数据，避免重复处理
     * - 创建通信UI界面
     * - 启动轮询机制，定期检查Python数据
     * 
     * 初始化步骤：
     * 1. 清理历史数据
     * 2. 创建UI界面
     * 3. 启动500ms轮询间隔
     */
    function initializeScript() {
        // 检查是否已经初始化过
        if (window.tampermonkeyInitialized) {
            console.log('油猴脚本已初始化，跳过重复初始化');
            return;
        }
        window.tampermonkeyInitialized = true;

        console.log('开始初始化油猴脚本...');

        // 清除历史数据，避免读取上次会话的消息
        localStorage.removeItem('tampermonkey_to_py');
        localStorage.removeItem('py_to_tampermonkey');
        console.log('已清除localStorage历史数据');

        // 尝试创建UI
        try {
            createUI();
            console.log('油猴UI创建成功');
        } catch (error) {
            console.error('油猴UI创建失败:', error);
            // UI创建失败不影响轮询功能
        }

        // 启动轮询
        pollPythonData();
        console.log('油猴脚本初始化完成');
    }

    // 策略1：如果DOM已经加载完成，立即初始化
    if (document.readyState === 'loading') {
        console.log('DOM正在加载，等待DOMContentLoaded事件');
        // 策略2：等待DOM加载完成
        document.addEventListener('DOMContentLoaded', function () {
            console.log('DOMContentLoaded事件触发，初始化脚本');
            initializeScript();
        });
    } else {
        console.log('DOM已加载完成，立即初始化脚本');
        // 策略3：DOM已经加载完成，直接初始化
        initializeScript();
    }

    // 策略4：延迟检查，确保页面完全加载
    setTimeout(() => {
        if (!window.tampermonkeyInitialized) {
            console.log('延迟1秒后初始化油猴脚本');
            initializeScript();
        }
    }, 1000);

    // 策略5：监听页面可见性变化，确保脚本在页面激活时运行
    document.addEventListener('visibilitychange', function () {
        if (document.visibilityState === 'visible' && !window.tampermonkeyInitialized) {
            console.log('页面变为可见状态，初始化脚本');
            initializeScript();
        }
    });

    // 策略6：监听页面聚焦事件
    window.addEventListener('focus', function () {
        if (!window.tampermonkeyInitialized) {
            console.log('页面获得焦点，初始化脚本');
            initializeScript();
        }
    });

    /**
     * 等待条件满足
     * @param {Function} testCondition - 测试条件函数，返回true时条件满足
     * @param {number} checkIntervalMillisecond - 检查间隔（毫秒）
     * @param {number} maxWaitCount - 最大等待次数，默认无限等待
     * @returns {Promise<boolean>} 返回true表示条件满足，false表示超时
     */
    function waitUntil(testCondition, checkIntervalMillisecond, maxWaitCount = Infinity) {
        return new Promise(resolve => {
            let count = 0;
            let id = setInterval(() => {
                count++;
                if (testCondition()) {
                    clearInterval(id);
                    resolve(true);
                } else if (count >= maxWaitCount) {
                    clearInterval(id);
                    console.warn(`waitUntil超时，最大等待次数：${maxWaitCount}`);
                    resolve(false);
                }
            }, checkIntervalMillisecond);
        });
    }
    function wait(millisecond) {
        return new Promise(resolve => setTimeout(resolve, millisecond));
    }
    /**
     * 自定义日志函数
     * @param {...any} args - 要记录的参数
     */
    function debugLog(...args) {
        if (!DEBUG) {
            console.log(...args);
        } else {
            // 同时输出到文件（在用户脚本环境中有限制，这里使用GM_xmlhttpRequest需要@grant权限）
            // 作为替代方案，我们可以将日志存储在localStorage中
            try {
                const timestamp = new Date().toISOString();
                const logMessage = `[${timestamp}] ${args.map(arg =>
                    typeof arg === 'object' ? JSON.stringify(arg) : String(arg)
                ).join(' ')}`;

                // 保存到localStorage
                const existingLogs = localStorage.getItem('aiMessengerDebugLogs') || '';
                const newLogs = existingLogs + logMessage + '\n';

                // 限制日志大小，只保留最近1000行
                const logsArray = newLogs.split('\n');
                if (logsArray.length > 1000) {
                    logsArray.splice(0, logsArray.length - 1000);
                }

                localStorage.setItem('aiMessengerDebugLogs', logsArray.join('\n'));
            } catch (e) {
                console.error('日志保存失败:', e);
            }
        }
    }

})();